/**
 * @file   SyncItem.java
 * @author Enrique Madrid <e.madrid@lpcsite.com>
 * @date   Thu Aug 30 13:19:34 2007
 * 
 * @brief  Item de sincronización
 * 
 * 
 */

package sim.sync;

import sim.utils.*;
import sim.utils.parser.*;

public final class SyncItem implements ParserScan {

    // Archivos de tipo texto.
    private static final byte[] TYPES_TXT = { 't', 'x', 't', 0,
					      's', 'q', 'l', 0,
					      'c', 'f', 'g', 0,
					      'l', 's', 't', 0,
					      'f', 'r', 'm', 0,
					      'r', 'e', 's' };
    // Archivos de tipo tablas ("sincronizables")
    private static final byte[] TYPES_TBL = { 't', 'b', 'l' };

    protected static final int TYPE_TXT = 1;
    protected static final int TYPE_BIN = 2;
    protected static final int TYPE_TBL = 3;

    protected static byte[] MODES = {'d', 'u', 'a', 'x'};

    protected static final int MODE_DELETE = 0; // 'd'
    protected static final int MODE_UPDATE = 1; // 'u'
    protected static final int MODE_APPEND = 2; // 'a'
    protected static final int MODE_REMAKE = 3; // 'x'
    protected static final int MODE_FIELDS = 4; // Actualización por campo.

    private static final int HIT_NAME = 1;
    private static final int HIT_MODE = 2;

    private int m_Hit;

    protected byte[] m_Name = null; // Si el nombre no existe, no se crea el item
    public int m_Type = TYPE_BIN; // Por defecto binario
    public int m_Mode = MODE_APPEND;	// Por defecto se añade
    public int m_Field = 0;


    protected SyncItem() {
    }

    public static SyncItem create(byte[] line, int start, int count) {
	Parser p;
	SyncItem item = null;
	item = new SyncItem();
	if (item != null) {	// Paranoia
	    item.m_Hit = HIT_NAME;
	    p = new Parser(item, Utils.TOKEN, Utils.TOKEN_SPACE, 1, Parser.PATTERN | Parser.FORWARD);
	    if (p != null) {	// Paranoia
		if (!p.scan(line, start, count)) {
		    item = null;
		}
		p = null;
	    }
	}
	return item;
    }

    public boolean parserHit(int hit, final byte[] line, int start, int length, Object something) {

	//#ifdef DEBUG_SYNCITEM
	//# System.out.println("SyncItem::parserHit() ENTERED");
	//#endif

	//#ifdef DEBUG_SYNCITEM
	//# System.out.println("\t" + new String(line, start, length));
	//#endif

	if (length > 0) {
	    switch (m_Hit) {
	    case HIT_NAME:
		setName(line, start, length);
		m_Hit = HIT_MODE;
		break;
	    case HIT_MODE:
		setMode(line, start, length);
		break;
	    }
	}

	//#ifdef DEBUG_SYNCITEM
	//# System.out.println("SyncItem::parserHit() EXITING");
	//#endif

	return true;
    }
    
    public boolean parserEnd(boolean cancel) {
	return (m_Name != null);
    }

    protected void setName(final byte[] line, int start, int count) {
	m_Name = null;

	// Establecer el nombre
	m_Name = new byte[count];
	Utils.memcpy(m_Name, 0, line, start, count);
	// Para establcer el tipo
	start = Utils.memmem(m_Name, 0, m_Name.length, Utils.TOKEN, Utils.TOKEN_POINT, 1);
	if (start > -1) {
	    start++;
	    setType(m_Name, start, m_Name.length - start);
	}	    
    }

    public String getName() {
	if (m_Name != null) {
	    return (new String(m_Name, 0, m_Name.length));
	}
	return null;
    }

    protected void setType(final byte[] line, int start, int count) {
	// Buscamos si es una tabla, son menos :-)
	if (Utils.memmem(TYPES_TBL, 0, TYPES_TBL.length,
			 line, start, count) > -1) {
	    m_Type = TYPE_TBL;
	} // Buscamos si es texto, son más ...
	else if (Utils.memmem(TYPES_TXT, 0, TYPES_TXT.length,
			      line, start, count) > -1) {
	    m_Type = TYPE_TXT;
	}
	else {
	    m_Type = TYPE_BIN;
	}
    }

    protected void setMode(byte[] line, int start, int count) {
	int mode;

	// Buscamos el tipo de actulizaición.
	mode = Utils.memmem(MODES, 0, MODES.length, line, start, 1);
	if ((mode > -1) && (mode < MODES.length)) {
	    // Actualizacion por registro.
	    m_Mode = mode;
	}
	else {
	    // Actulización por campo.
	    m_Field = Utils.memtoul(line, start, count, 10);
	    if (m_Field > 0) {
		m_Mode = MODE_FIELDS;
	    }
	}

    }

}
